package cn.com.waajyun.shanbayscan.controller;

import cn.com.waajyun.shanbayscan.cache.CacheMap;
import cn.com.waajyun.shanbayscan.dto.ArticleDto;
import cn.com.waajyun.shanbayscan.dto.ArticlesDto;
import cn.com.waajyun.shanbayscan.service.ArticleService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping("article")
public class ArticleController {

    @Autowired
    private ArticleService articleService;

    @GetMapping
    public String postArticles(ModelMap modelMap) throws IOException {
        List<ArticleDto> list = (List<ArticleDto>) CacheMap.get("cachedArticles");
        Date updateCacheTime = (Date) CacheMap.get("updateCacheTime");
        if (list == null || list.isEmpty()) {
            updateCacheTime = new Date();
            CacheMap.put("cachedArticles", articleService.getPageContent(1, null, true));
            CacheMap.put("updateCacheTime", updateCacheTime);
            list = (List<ArticleDto>) CacheMap.get("cachedArticles");
        }
        modelMap.putAll(handleArticles(list, false, null));
        modelMap.putAll(handleArticles(list, true, "today"));
        modelMap.put("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(updateCacheTime));
        return "article/post";
    }

    private Map<String, Object> handleArticles(List<ArticleDto> srcArticles, boolean isToday, String prefix) {
        Map<String, Object> handleMap = Maps.newHashMap();
        Map<String, Map<String, List<ArticleDto>>> authorIdTable = Maps.newHashMap();
        Map<String, ArticlesDto> result = Maps.newHashMap();
        List<ArticleDto> waitHandledArticles = Lists.newArrayList(srcArticles);
        for (ArticleDto articleDto : waitHandledArticles) {
            if (isToday && (articleDto.getTopicPostTime() == null || !isSameDay(articleDto.getTopicPostTime(), new Date())))
                continue;
            if (articleDto.getAuthor() != null) {
                if (!authorIdTable.containsKey(articleDto.getAuthor().getId())) {
                    authorIdTable.put(articleDto.getAuthor().getId(), Maps.newHashMap());
                }
                Map<String, List<ArticleDto>> authorsTable = authorIdTable.get(articleDto.getAuthor().getId());
                if (!authorsTable.containsKey(articleDto.getAuthor().getNickname())) {
                    authorsTable.put(articleDto.getAuthor().getNickname(), Lists.newArrayList());
                }
                authorsTable.get(articleDto.getAuthor().getNickname()).add(articleDto);
                List<ArticleDto> articles;
                if (!result.containsKey(articleDto.getAuthor().getNickname())) {
                    ArticlesDto articlesDto = new ArticlesDto();
                    articles = Lists.newArrayList();
                    articlesDto.setAuthor(articleDto.getAuthor());
                    articlesDto.setArticles(articles);
                    result.put(articleDto.getAuthor().getNickname(), articlesDto);
                } else {
                    articles = result.get(articleDto.getAuthor().getNickname()).getArticles();
                }
                articles.add(articleDto);
            }
        }
        for (Map.Entry<String, Map<String, List<ArticleDto>>> authorId : authorIdTable.entrySet()) {
            if (authorId.getValue().size() > 1) {
                String usedAuthorName = null;
                int postCount = 0;
                for (Map.Entry<String, List<ArticleDto>> articleTable : authorId.getValue().entrySet()) {
                    if (articleTable.getValue().size() > postCount) {
                        usedAuthorName = articleTable.getKey();
                        postCount = articleTable.getValue().size();
                    }
                }
                for (Map.Entry<String, List<ArticleDto>> articleTable : authorId.getValue().entrySet()) {
                    if (!usedAuthorName.equals(articleTable.getKey())) {
                        result.get(usedAuthorName).getArticles().addAll(articleTable.getValue());
                        result.remove(articleTable.getKey());
                        for (ArticleDto articleDto : articleTable.getValue()) {
                            articleDto.getAuthor().updateNickName(usedAuthorName);
                        }
                    }
                }
            }
        }
        List<ArticlesDto> articlesDtos = Lists.newArrayList(result.values());
        Collections.sort(articlesDtos, new Comparator<ArticlesDto>() {
            @Override
            public int compare(ArticlesDto o1, ArticlesDto o2) {
                return o2.getArticlesTotal() - o1.getArticlesTotal();
            }
        });
        handleMap.put(StringUtils.isBlank(prefix) ? "articles" : prefix + "Articles", articlesDtos);
        handleMap.put(StringUtils.isBlank(prefix) ? "total" : prefix + "Total", result.size());
        return handleMap;
    }

    private boolean isSameDay(Date d1, Date d2) {
        Calendar calDateA = Calendar.getInstance();
        calDateA.setTime(d1);
        Calendar calDateB = Calendar.getInstance();
        calDateB.setTime(d2);
        return calDateA.get(Calendar.YEAR) == calDateB.get(Calendar.YEAR)
                && calDateA.get(Calendar.MONTH) == calDateB.get(Calendar.MONTH)
                && calDateA.get(Calendar.DAY_OF_MONTH) == calDateB
                .get(Calendar.DAY_OF_MONTH);
    }

}
